package com.example.sm2.cipher.sm2;

import org.bouncycastle.asn1.*;
import org.bouncycastle.asn1.x509.X509CertificateStructure;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.encoders.Hex;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.spec.ECGenParameterSpec;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;

public class Test {
    public static void main(String[] args) throws Exception {
        //生成密钥对
        String[] strings = SM2Utils2.generateSmKey();
        //公钥
        System.out.println(strings[0]);
        //私钥
        System.out.println(strings[1]);
        //将base64的字符串转换成公钥
        PublicKey publicKey = createPublicKey(strings[0]);
        //将base64的字符串转换成私钥
        PrivateKey privateKey = createPrivateKey(strings[1]);
        //私钥签名，公钥验签
        System.out.println("测试私钥签名、公钥验签");
        byte[] sign = SM2Utils2.signByPrivateKey("小明".getBytes(), privateKey);
        boolean b = SM2Utils2.verifyByPublicKey("小明".getBytes(), publicKey, sign);
        System.out.println("验签结果:"+b);
        //解析公钥
        SM2Utils2.resolveSM2(strings[0]);
        System.out.println("-------------");
        //使用公钥加密数据
        byte[] bytes= SM2Utils2.encrypt(new String("你好").getBytes(StandardCharsets.UTF_8), createPublicKey(strings[0]));
        //使用私密解密数据
        byte[] decrypt = SM2Utils2.decrypt(bytes, createPrivateKey(strings[1]));
        //输出解密后的数据
        System.out.println(new String(decrypt));

        System.out.println("-------------------------------");
        System.out.println("-------------------------------");

        //base64 16进制互转
        //base64 转 byte[]
        String src = "MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAEsFJ6DWqcI9JORsV3aG/54fyfZwmYGHLHeXqGPDxn3jFJbrXAdgV3cyfUEy9E9ftHPVYj/Yv2i1PSoNIxhBTL2w==";
        System.out.println("原base64："+src);
        byte[] base64 = Base64.getDecoder().decode(src);
        //byte[] 转 16进制
        String hexString = Hex.toHexString(base64);
        System.out.println("16进制："+hexString);
        //16进制 转 byte[]
        byte[] hex = Hex.decode(hexString);
        //byte[] 转 base64
        String base64String = Base64.getEncoder().encodeToString(hex);
        System.out.println("转回原base64："+base64String);

    }

    public static void resolveSM2(String key){
        byte[] decode = Base64.getDecoder().decode(key);
        ASN1InputStream ais = new ASN1InputStream(decode);
        ASN1Primitive primitive = null;
        try {
            while((primitive=ais.readObject())!=null){
                System.out.println("sequence->"+primitive);
                if(primitive instanceof ASN1Sequence){
                    ASN1Sequence sequence = (ASN1Sequence)primitive;
                    ASN1SequenceParser parser = sequence.parser();
                    ASN1Encodable encodable = null;
                    while((encodable=parser.readObject())!=null){
                        primitive = encodable.toASN1Primitive();
                        System.out.println("prop->"+primitive);
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            try {
                ais.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 将Base64转码的公钥串，转化为公钥对象
     *
     * @param publicKey
     * @return
     */
    public static PublicKey createPublicKey(String publicKey) {
        PublicKey publickey = null;
        try{
            X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(Base64.getDecoder().decode(publicKey));
            KeyFactory keyFactory = KeyFactory.getInstance("EC", new BouncyCastleProvider());
            publickey = keyFactory.generatePublic(publicKeySpec);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return publickey;
    }

    /**
     * 将Base64转码的私钥串，转化为私钥对象
     *
     * @param privateKey
     * @return
     */
    public static PrivateKey createPrivateKey(String privateKey) {
        PrivateKey publickey = null;
        try{
            PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKey));
            KeyFactory keyFactory = KeyFactory.getInstance("EC", new BouncyCastleProvider());
            publickey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return publickey;
    }


    private byte[] getCSPK(byte[] csCert)
    {
        InputStream inStream = new ByteArrayInputStream(csCert);
        ASN1Sequence seq = null;
        ASN1InputStream aIn;
        try
        {
            aIn = new ASN1InputStream(inStream);
            seq = (ASN1Sequence)aIn.readObject();
            X509CertificateStructure cert = new X509CertificateStructure(seq);
            cert.getVersion();
            ASN1Primitive publicKey = cert.getSubjectPublicKeyInfo().getPublicKey();
            byte[] encodedPublicKey = publicKey.getEncoded();
            byte[] eP = new byte[64];
            System.arraycopy(encodedPublicKey, 5, eP, 0, eP.length);
            return eP;
        }
        catch (Exception e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return null;
    }

    public static String[] generateSmKey() throws Exception {
        KeyPairGenerator keyPairGenerator = null;
        SecureRandom secureRandom = new SecureRandom();
        ECGenParameterSpec sm2Spec = new ECGenParameterSpec("sm2p256v1");
        keyPairGenerator = KeyPairGenerator.getInstance("EC", new BouncyCastleProvider());
        keyPairGenerator.initialize(sm2Spec);
        keyPairGenerator.initialize(sm2Spec, secureRandom);
        KeyPair keyPair = keyPairGenerator.generateKeyPair();
        PrivateKey privateKey = keyPair.getPrivate();
        PublicKey publicKey = keyPair.getPublic();
        String[] result = {
                new String(Base64.getEncoder().encode(publicKey.getEncoded()))
                , new String(Base64.getEncoder().encode(privateKey.getEncoded()))
        };
        return result;
    }
}
